﻿using MySqlX.XDevAPI.Common;
using Photo.Application.System.Role.Dto;
using Photo.Core.SeedData;

namespace Photo.Application.System.Role
{
    /// <summary>
    /// 系统角色
    /// </summary>
    [ApiDescriptionSettings(ApiGroupConsts.System, Module = ApiGroupConsts.System)]
    public class RoleService : IDynamicApiController
    {
        private readonly IRepository<SysRoleEntity> _sysRoleRepository;
        private readonly IRepository<SysUserRoleEntity> _sysUserRoleRepository;
        private readonly IRepository<SysRoleMenuEntity> _sysRoleMenuRepository;
        private readonly IRepository<SysRoleSecurityEntity> _sysRoleSecurityRepository;
        public RoleService(IRepository<SysRoleEntity> sysRoleRepository, IRepository<SysUserRoleEntity> sysUserRoleRepository, IRepository<SysRoleMenuEntity> sysRoleMenuRepository, IRepository<SysRoleSecurityEntity> sysRoleSecurityRepository)
        {
            _sysRoleRepository = sysRoleRepository;
            _sysUserRoleRepository = sysUserRoleRepository;
            _sysRoleMenuRepository = sysRoleMenuRepository;
            _sysRoleSecurityRepository = sysRoleSecurityRepository;
        }

        /// <summary>
        /// 添加系统角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public async Task Add(RoleSaveInput input)
        {
            await MutexUtil.MutexNoWait("/api/system/role/add", async () =>
            {
                if (await _sysRoleRepository.AnyAsync(o => o.Name == input.Name))
                    throw Oops.Oh("角色名称重复");

                var entity = input.Adapt<SysRoleEntity>();
                
                await _sysRoleRepository.InsertAsync(entity);
            });
        }

        /// <summary>
        /// 修改系统角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public async Task Edit(RoleSaveInput input)
        {
            await MutexUtil.MutexNoWait("/api/system/role/edit?" + input.Id, async () =>
            {
                if (await _sysRoleRepository.AnyAsync(o => o.Id != input.Id && o.Name == input.Name))
                    throw Oops.Oh("角色名称重复");

                var entity = await _sysRoleRepository.GetAsync(input.Id, "当前角色不存在");
                entity.Name = input.Name;
                entity.IsActive = input.IsActive;
                entity.Sort = input.Sort;

                await _sysRoleRepository.UpdateAsync(entity);
            });
        }

        /// <summary>
        /// 删除系统角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [UnitOfWork]
        [SecurityDefine]
        public async Task Del(PrimaryKey input)
        {
            await MutexUtil.MutexNoWait("/api/system/role/del?" + input.Id, async () =>
            {
                //1.删除角色
                var entity = await _sysRoleRepository.GetAsync(input.Id, "当前角色不存在");
                await _sysRoleRepository.DeleteAsync(entity);

                //2.删除角色用户关联表数据
                await _sysUserRoleRepository.DeleteAsync(o => o.RoleId == entity.Id);

                //3.删除角色菜单关联表数据
                await _sysRoleMenuRepository.DeleteAsync(o => o.RoleId == entity.Id);

                //4.删除角色权限关联表
                await _sysRoleSecurityRepository.DeleteAsync(o => o.RoleId == entity.Id);

            });
        }

        /// <summary>
        /// 设置角色有效性
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public async Task SetActive(PrimaryKey input)
        {
            await MutexUtil.MutexNoWait("/api/system/role/setactive?" + input.Id, async () =>
            {
                var entity = await _sysRoleRepository.GetAsync(input.Id, "当前角色不存在");

                entity.IsActive = !entity.IsActive;

                await _sysRoleRepository.UpdateAsync(entity);
            });
        }

        /// <summary>
        /// 设置角色权限
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [UnitOfWork]
        [SecurityDefine]
        public async Task SetRolePermission(RoleSetPermissionInput input)
        {
            await MutexUtil.MutexNoWait("/api/system/role/setrolepermission?" + input.Id, async () =>
            {
                var entity = await _sysRoleRepository.GetAsync(input.Id, "当前角色不存在");

                //1.删除历史数据
                await _sysRoleMenuRepository.DeleteAsync(o => o.RoleId == entity.Id);
                await _sysRoleSecurityRepository.DeleteAsync(o => o.RoleId == entity.Id);

                //2.添加新数据
                var roleMenuList = input.MenuIds.Select(o => new SysRoleMenuEntity
                {
                    RoleId = entity.Id,
                    MenuId = o
                }).ToList();
                await _sysRoleMenuRepository.InsertAsync(roleMenuList);

                //3.添加新数据
                var roleSecurityList = input.SecurityList.Select(o => new SysRoleSecurityEntity
                {
                    RoleId = entity.Id,
                    Security = o
                }).ToList();
                await _sysRoleSecurityRepository.InsertAsync(roleSecurityList);

            });
        }

        /// <summary>
        /// 获取角色权限列表
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public async Task<RolePermissionOutput> GetRolePermissionList(PrimaryKey input)
        {
            if (!(await _sysRoleRepository.AnyAsync(o => o.Id == input.Id)))
                throw Oops.Oh("当前角色不存在");

            var result = new RolePermissionOutput();

            //所有菜单列表
            var allMenuList = SysMenuSeedData.SeedDataList;

            //排除父级角色菜单对应数据(树菜单在父级选中时会全选子集)
            var pIds = allMenuList
                .Where(o => allMenuList.Where(x => x.PUnique == o.Unique).Any())
                .Select(o => o.Unique)
                .Distinct()
                .ToList();

            //已存储的菜单id
            result.MenuIds = await _sysRoleMenuRepository.Query()
                .Where(o => o.RoleId == input.Id)
                .Where(o => !pIds.Contains(o.MenuId))
                .Select(o => o.MenuId)
                .ToListAsync();

            //已存储的权限id
            result.SecurityList = await _sysRoleSecurityRepository.Query()
                .Where(o => o.RoleId == input.Id)
                .Select(o => o.Security)
                .ToListAsync();

            //所有菜单树列表
            result.MenuTreeList = SysMenuSeedData.SeedDataEleTree;

            //所有权限列表
            result.SecurityTreeList = SysSecuritySeedData.GetEleTreeList();

            return result;
        }

        /// <summary>
        /// 获取角色列表
        /// </summary>
        /// <returns></returns>
        [SecurityDefine]
        public async Task<List<RoleDto>> GetList()
        {
            return await _sysRoleRepository.GetListAsync<RoleDto>(null, o => o.Sort, OrderByType.Asc);
        }

        /// <summary>
        /// 获取角色详情
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [SecurityDefine]
        public async Task<RoleDto> GetInfo(PrimaryKey input)
        {
            return await _sysRoleRepository.GetAsync<RoleDto>(input.Id, "当前角色不存在");
        }

    }
}
